<!-- 中间面板组件包围 -->
<template>

    <div class="component-wrap" :key="item.id" :id="item.id"
        :class="{ active: item.active, free: item.layoutType === 'free' }" :style="item.layoutType == 'free' ? 
        {left: item.x + 'px', 
         top: item.y + 'px',
         width: item.width + 'px', 
         height: item.height + 'px',
         zIndex: item.componentProps.style.zIndex} 
        : {}" @click="handleClickItem">

        <!-- 虚拟层 用于拖拽大小展示效果 -->
        <div v-show="data.resizing" ref="overlayBox" class="resize-overlay" />

        <!-- 拖动句柄 -->
        <div v-if="item.layoutType == 'free' && item.active" v-for="(handle, index) in handles" :key="index"
            :class="handle.class" @mousedown.prevent="startResizing($event,handle)">
        </div>

        <div class="action-box" :class="{bottom: data.actionBoxBottom}" v-show="item.active">
            <span class="component-name">{{ item.name }}</span>
            <a class="action-btn" @click="$emit('copyComponent',item,$event)" title="复制">
                <CopyOutlined />
            </a>
            <a class="action-btn" @click="$emit('deleteComponent',item,$event)" title="删除">
                <DeleteOutlined />
            </a>
        </div>

        <template v-if="item.children != undefined">
            <!-- 单独适配栅格布局 -->
            <template v-if="item.type == 'gridLayout'">
                <component :is="getComponent()" :item="item" @dragStart="dragStart" @clearOtherActive="clearOtherActive"
                    @copyComponent="copyComponent" @deleteComponent="deleteComponent"
                    @handleSetSelectItem="handleSetSelectItem" @addChildComponent="addChildComponent" :key="item.id">
                    <template #content>
                        <!-- row下面的col -->
                        <component v-for="childItem in item.children" :is="getItemComponent(childItem)"
                            :item="childItem" @dragStart="dragStart" @dragEnd="dragEnd"
                            @clearOtherActive="clearOtherActive" @copyComponent="copyComponent"
                            @deleteComponent="deleteComponent" @handleSetSelectItem="handleSetSelectItem"
                            @addChildComponent="addChildComponent" :key="childItem.id">
                            <template #content>
                                <draggable tag="div" :list="childItem.children" class="dragColArea"
                                    v-bind="data.dragOption" @add="$emit('addChildComponent',$event,childItem)"
                                    @start="$emit('dragStart',$event, childItem.children)"
                                    @end="$emit('dragEnd',$event, childItem.children)">
                                    <template #item="{ element,index }">
                                        <componentWrap ref="childItem" :item="element" @clearActive="clearActiveItem"
                                            @dragStart="dragStart" @dragEnd="dragEnd"
                                            @clearOtherActive="clearOtherActive" @copyComponent="copyComponent"
                                            @deleteComponent="deleteComponent"
                                            @handleSetSelectItem="handleSetSelectItem"
                                            @addChildComponent="addChildComponent" :key="element.id">
                                        </componentWrap>
                                    </template>
                                </draggable>
                            </template>
                        </component>
                    </template>
                </component>
            </template>

            <template v-else>
                <component :is="getComponent()" :item="item" @dragStart="dragStart" @dragEnd="dragEnd"
                    @clearOtherActive="clearOtherActive" @copyComponent="copyComponent"
                    @deleteComponent="deleteComponent" @handleSetSelectItem="handleSetSelectItem"
                    @addChildComponent="addChildComponent" :key="item.id">
                    <template #content>
                        <draggable tag="div" :list="item.children" class="dragArea" v-bind="data.dragOption"
                            @add="$emit('addChildComponent',$event,item)" @end="$emit('dragEnd',$event, item.children)"
                            @start="$emit('dragStart',$event, item.children)">
                            <template #item="{ element,index }">
                                <componentWrap ref="childItem" :item="element" @clearActive="clearActiveItem"
                                    @dragStart="dragStart" @dragEnd="dragEnd" @clearOtherActive="clearOtherActive"
                                    @copyComponent="copyComponent" @deleteComponent="deleteComponent"
                                    @handleSetSelectItem="handleSetSelectItem" @addChildComponent="addChildComponent"
                                    :key="element.id"></componentWrap>
                            </template>
                        </draggable>
                    </template>
                </component>
            </template>
        </template>

        <template v-else>
            <componentItem :item="item" @clearActive="$emit('clearActiveItem')"
                @handleSetSelectItem="$emit('handleSetSelectItem')" :key="item.id"></componentItem>
        </template>
    </div>

</template>

<script setup> 
import { ref, reactive, watch, defineProps, onMounted, onUnmounted } from 'vue'
import componentItem from './componentItem.vue'
import draggable from "vuedraggable"
import { getComponentInstance } from '../../componentManager.js'
import { storage } from '../../pageManager.js'

const emit = defineEmits(['handleSetSelectItem', 'copyComponent', 'deleteComponent', 'clearOtherActive', 'addChildComponent', 'dragStart', 'dragEnd'])

// 虚拟层
const overlayBox = ref(null)

defineOptions({
    name: 'componentWrap'
})

const props = defineProps({
    item: {
        type: Object,
        default: undefined
        // required: true
    },
    selectItem: {
        type: Object,
    },
})

const data = reactive({
    dragOption: {
        group: { name: 'form-draggable' },
        ghostClass: 'moving',
        animation: 180,
        handle: '',
    },
    actionBoxBottom: false,
    // 初始宽高
    divWidth: props.initialWidth + 'px',
    divHeight: props.initialHeight + 'px',
    // 鼠标位置
    mousePosition: { x: 0, y: 0 },
    storage: { width: 0, height: 0, top: 0, left: 0 },
    currentHandle: null,   // 当前拖动的句柄
    resizing: false,       // 是否正在拖动大小
    changed: false,        // 是否改变了大小
})

// 拖动句柄
const handles = [
    { class: 'handle nw' },   // 左上
    { class: 'handle n' },    // 中上
    { class: 'handle ne' },   // 右上
    { class: 'handle e' },    // 右中
    { class: 'handle se' },   // 右下
    { class: 'handle s' },    // 下中
    { class: 'handle sw' },   // 左下
    { class: 'handle w' },    // 左中
]

onMounted(() => {
    setActionBoxPosition();
    if (props.item.layoutType == 'free') {
        setOverlaySize()
    }
})

onUnmounted(() => {
    document.removeEventListener('mousemove', resizing)
    document.removeEventListener('mouseup', stopResizing)
})


// 设置虚拟层的尺寸
const setOverlaySize = () => {
    let itemEvt = document.getElementById(props.item.id)
    let itemRect = itemEvt.getBoundingClientRect()

    overlayBox.value.style.top = "0px"
    overlayBox.value.style.left = "0px"
    overlayBox.value.style.width = itemRect.width + "px"
    overlayBox.value.style.height = itemRect.height + "px"
}


/**
 * 开始拖拽大小
 * @param {*} e 鼠标实例 
 * @param {*} handle 句柄
 */
const startResizing = (e, handle) => {

    setOverlaySize()

    // 进入拖拽大小状态
    data.resizing = true
    // 当前拖动的句柄
    data.currentHandle = handle

    // 鼠标位置
    data.mousePosition.x = e.clientX
    data.mousePosition.y = e.clientY

    // 当前组件
    let currentItem = document.getElementById(props.item.id)

    // 暂存大小
    data.storage.width = currentItem.offsetWidth
    data.storage.height = currentItem.offsetHeight
    // 暂存位置
    data.storage.top = currentItem.offsetTop
    data.storage.left = currentItem.offsetLeft

    document.addEventListener('mousemove', resizing)
    document.addEventListener('mouseup', stopResizing)
}

/**
 * 鼠标移动时正在拖拽大小
 * @param {*} e 鼠标实例
 */
const resizing = (e) => {
    if (!data.resizing) return

    // 当前拖拽句柄
    let handle = data.currentHandle

    let x = e.clientX - data.mousePosition.x
    let y = e.clientY - data.mousePosition.y

    let left = data.storage.left + x
    let top = data.storage.top + y

    switch (handle.class) {
        case 'handle nw': // 左上
            if (data.storage.height - y > 0 && data.storage.width - x > 0) {
                overlayBox.value.style.width = data.storage.width - x + "px"
                overlayBox.value.style.height = data.storage.height - y + "px"
                overlayBox.value.style.top = y + "px"
                overlayBox.value.style.left = x + "px"
            }
            data.changed = true
            break
        case 'handle n':  // 上中
            if (data.storage.height - y > 0) {
                overlayBox.value.style.height = data.storage.height - y + "px"
                overlayBox.value.style.top = y + "px"
            }
            data.changed = true
            break
        case 'handle ne': // 右上
            if (data.storage.height - y > 0) {
                overlayBox.value.style.width = data.storage.width + x + "px"
                overlayBox.value.style.height = data.storage.height - y + "px"
                overlayBox.value.style.top = y + "px"
            }
            data.changed = true
            break
        case 'handle e':  // 右中
            overlayBox.value.style.width = data.storage.width + x + "px"
            data.changed = true
            break
        case 'handle se': // 右下
            overlayBox.value.style.width = data.storage.width + x + "px"
            overlayBox.value.style.height = data.storage.height + y + "px"
            data.changed = true

            break
        case 'handle s':  // 下中
            overlayBox.value.style.height = data.storage.height + y + "px"
            data.changed = true
            break
        case 'handle sw': // 左下
            if (data.storage.width - x > 0) {
                overlayBox.value.style.width = data.storage.width - x + "px"
                overlayBox.value.style.height = data.storage.height + y + "px"
                overlayBox.value.style.left = x + "px"
            }
            data.changed = true
            break
        case 'handle w':  // 左中
            if (data.storage.width - x > 0) {
                overlayBox.value.style.width = data.storage.width - x + "px"
                overlayBox.value.style.left = x + "px"
            }
            data.changed = true
            break
    }

}

/**
 *  停止拖拽大小
 */
const stopResizing = () => {

    if (!data.resizing) return

    data.resizing = false

    // 当前拖拽句柄
    let handle = data.currentHandle
    let currentItem = document.getElementById(props.item.id)

    let x = parseInt(overlayBox.value.style.left.slice(0, -2))
    let y = parseInt(overlayBox.value.style.top.slice(0, -2))

    let left = data.storage.left + x
    let top = data.storage.top + y

    if (data.changed) {
        switch (handle.class) {
            case 'handle nw': // 左上
                currentItem.style.width = overlayBox.value.style.width
                currentItem.style.height = overlayBox.value.style.height
                currentItem.style.top = top + 'px'
                currentItem.style.left = left + 'px'
                break
            case 'handle n':  // 上中
                currentItem.style.height = overlayBox.value.style.height
                currentItem.style.top = top + 'px'
                data.changed = false
                break
            case 'handle ne': // 右上
                currentItem.style.width = overlayBox.value.style.width
                currentItem.style.height = overlayBox.value.style.height
                currentItem.style.top = top + 'px'
                data.changed = false
                break
            case 'handle e':  // 右中
                currentItem.style.width = overlayBox.value.style.width
                data.changed = false
                break
            case 'handle se': // 右下
                currentItem.style.width = overlayBox.value.style.width
                currentItem.style.height = overlayBox.value.style.height
                data.changed = false
                break
            case 'handle s':  // 下中
                currentItem.style.height = overlayBox.value.style.height
                data.changed = false
                break
            case 'handle sw': // 左下
                currentItem.style.width = overlayBox.value.style.width
                currentItem.style.height = overlayBox.value.style.height
                currentItem.style.left = left + 'px'
                break
            case 'handle w':  // 左中
                currentItem.style.width = overlayBox.value.style.width
                currentItem.style.left = left + 'px'
                data.changed = false
                break
        }

        // props.item.x = parseInt(overlayBox.value.style.left.slice(0, -2));
        props.item.x = left
        // props.item.y = parseInt(overlayBox.value.style.top.slice(0, -2));
        props.item.y = top
        props.item.width = parseInt(overlayBox.value.style.width.slice(0, -2))
        props.item.height = parseInt(overlayBox.value.style.height.slice(0, -2))

        //  || props.item.groupName == '基础表格'
        // TODO 基础表格宽高适配问题 
        if (props.item.groupName == '基础图形') {
            props.item.componentProps.style.width = props.item.width
            props.item.componentProps.style.height = props.item.height
        }


    }

    // 清空当前拖拽句柄
    data.currentHandle = null

    storage.resizeTrigger = true

    document.removeEventListener('mousemove', resizing)
    document.removeEventListener('mouseup', stopResizing)
}



// 获取异步加载的组件
const getComponent = () => {
    let cmpI = getComponentInstance(props.item.type)
    return cmpI.component
}

// 获取指定的组件
const getItemComponent = (childItem) => {
    let cmpI = getComponentInstance(childItem.type)
    return cmpI.component
}

// 设置组件操作框的位置
const setActionBoxPosition = () => {
    console.log("props.item::", props.item)
    if (props.item.id) {
        let editPanelRect = document.getElementById('center-panel').getBoundingClientRect()
        let itemEvtRect = document.getElementById(props.item.id).getBoundingClientRect()
        let top = itemEvtRect.top - editPanelRect.top
        if (top < 28) {
            data.actionBoxBottom = true
        } else {
            data.actionBoxBottom = false
        }
    }
}

/**
* @method
* @param {Object} event 当前实例对象
* @desc 点击组件
*/
const handleClickItem = (event) => {
    setActionBoxPosition()
    props.item.active = true
    // 设置当前组件的选中
    emit("handleSetSelectItem", props.item)
    // 清除其它组件的点击状态
    // this.$emit("clearOtherActive", this.item.key);
    // 阻止底层元素事件
    event.stopPropagation()
}

/**
* @method
* @param {Object} item 组件对象
* @desc 设置选中组件
*/
const handleSetSelectItem = (item) => {
    emit("handleSetSelectItem", item)
}

/**
* @method
* @param {Object} item 组件对象
* @desc 复制组件
*/
const copyComponent = (item, event) => {
    emit("copyComponent", item, event)
}

/**
* @method
* @param {Object} item 组件对象
* @param {Object} event 当前实例对象
* @desc 删除组件
*/
const deleteComponent = (item, event) => {
    emit("deleteComponent", item, event)
}


/**
* @method
* @param {Object} id 组件ID值
* @desc 清除其它组件的点击状态
*/
const clearOtherActive = (id) => {
    emit("clearOtherActive", id)
}

/**
* @method
* @param {Object} evt 当前实例对象
* @param {Object} item 组件对象
* @desc 添加子组件
*/
const addChildComponent = (evt, item) => {
    emit("addChildComponent", evt, item)
}

/**
* @method
* @param {Object} evt 当前实例对象
* @param {Object} list 组件对象
* @desc 拖拽开始
*/
const dragStart = (evt, list) => {
    emit("dragStart", evt, list)
}

/**
* @method
* @param {Object} evt 当前实例对象
* @param {Object} list 组件对象
* @desc 拖拽结束
*/
const dragEnd = (evt, list) => {
    emit("dragEnd", evt, list)
}


</script>

<style lang="less" scoped>
.component-wrap {
    width: auto;
    height: auto;
    cursor: move;
    position: relative;

    &.free {
        position: absolute !important;
    }

    &.active {
        border: 1px dashed #3e8bf2;
        background-color: rgba(62, 139, 242, 0.06);
    }

    .free-handle {
        position: absolute;
        width: 100px;
        height: 20px;
        border-radius: 5px;
        border: 1px solid var(--borderColor);
        background-color: #fafafa;
        top: -24px;
        left: 0;
    }

    .action-box {
        position: absolute;
        z-index: 999;
        width: auto;
        height: 25px;
        border-radius: 4px 4px 0 0;
        color: #fff;
        display: flex;
        align-items: center;
        padding: 0 5px;
        top: -24px;
        right: 0;
        cursor: default;

        &.bottom {
            top: unset;
            bottom: -24px;
        }

        .component-name {
            font-size: 12px;
            color: #0c64d8;
        }

        .action-btn {
            color: #0c64d8;
            cursor: pointer;
            font-size: 13px;
            margin-left: 5px;
        }
    }
}
</style>